//
//  YHToastPopView.swift
//  FuweiCloud
//
//  Created by michael on 2024/10/16.
//

import UIKit
#if canImport(SnapKit)
import SnapKit
#endif

public enum YHToastPopViewType: Int {
  case none
  case loading
  case failed
  case succeeded
}

@objcMembers
open class YHToastPopView: YHPopView {
  // MARK: - Properties
    
  public var topMargin: CGFloat = 20
  public var bottomMargin: CGFloat = 20
  public var topPadding: CGFloat = 20
  public var bottomPadding: CGFloat = 20
  public var headerPadding: CGFloat = 30
  public var headerWidth: CGFloat = 64
  public var headerHeight: CGFloat = 0
  public var headerHorizon: Bool = false
  public var headerAlign: NSTextAlignment = .center
  public var bodyPadding: CGFloat = 30
  public var bodyWidth: CGFloat = 60
  public var bodyHeight: CGFloat = 100
  public var bodyHorizon: Bool = false
  public var bodyAlign: NSTextAlignment = .center
  public var footerPadding: CGFloat = 30
  public var footerWidth: CGFloat = 160
  public var footerHeight: CGFloat = 45
  public var footerHorizon: Bool = false
  public var fitHeight: Bool = false
  public var header: Any?
  public var body: Any?
  public var footer: Any?
  public var timeout: TimeInterval = 0
  public var timeoutBlock: (() -> Void)?
    
  private(set) var headerView: UIView?
  private(set) var bodyView: UIView?
  private(set) var footerView: UIView?
    
  private var timer: YHTimer?
    
  // MARK: - Initialization
    
  private func initProperties() {
    if let userInfo = userInfo as? [String: Any] {
      for (key, value) in userInfo where key.hasPrefix("YHPop") {
        let k = String(key.dropFirst(5))
        if responds(to: Selector("set\(k):")) {
          setValue(value, forKey: k.uncapitalized)
        }
      }
    }
    if timeout > 0 {
      timer = YHTimer(fireTime: timeout) { [weak self] _, _ in
        self?.timeoutBlock?()
        self?.timeoutBlock = nil
        self?.dismiss()
      }
    }
  }
    
  // MARK: - UI Setup
    
  public override func initContentUI() {
    initProperties()
    contentWidth = min(Self.maxPopWidth, YHScreenH) - 90
    contentHeight = 220
    headerView = viewWithData(header, type: 0)
    bodyView = viewWithData(body, type: 1)
    footerView = viewWithData(footer, type: 2)
        
    let count = [headerView, bodyView, footerView].compactMap { $0 }.count
    var insetSpace: CGFloat = 0
        
    switch count {
    case 3:
      insetSpace = topPadding + bottomPadding
    case 2:
      if headerView != nil {
        if footerView != nil && headerHeight < 30 {
          topPadding = min(40, topPadding + 20)
        }
        insetSpace = topPadding
      } else if bodyView != nil {
        if footerView != nil && bodyHeight < 30 {
          bottomPadding = min(40, bottomPadding + 20)
        }
        insetSpace = bottomPadding
      }
    default:
      break
    }
        
    var fitHeight = headerHeight + bodyHeight + footerHeight + insetSpace + topMargin + bottomMargin
    if !self.fitHeight {
      let diff = max(0, (contentHeight - fitHeight) / 2)
      topMargin += diff
      bottomMargin += diff
      fitHeight = max(contentHeight, fitHeight)
    }
        
    contentHeight = fitHeight
#if canImport(SnapKit)
    contentView.snp.updateConstraints { make in
      make.height.equalTo(contentHeight)
    }
#endif
    setupHeaderView()
    setupBodyView()
    setupFooterView()
  }
    
  private func setupHeaderView() {
    guard let headerView = headerView else { return }
    contentView.addSubview(headerView)
#if canImport(SnapKit)
    headerView.snp.makeConstraints { make in
      if headerHorizon {
        make.width.equalTo(headerWidth)
        make.centerX.equalToSuperview()
      } else {
        make.left.equalTo(headerPadding)
        make.right.equalTo(-headerPadding)
      }
      make.top.equalTo(topMargin)
      make.height.equalTo(headerHeight)
    }
#endif
  }
    
  private func setupBodyView() {
    guard let bodyView = bodyView else { return }
    contentView.addSubview(bodyView)
#if canImport(SnapKit)
    bodyView.snp.makeConstraints { make in
      if bodyHorizon {
        make.width.equalTo(bodyWidth)
        make.centerX.equalToSuperview()
      } else {
        make.left.equalTo(bodyPadding)
        make.right.equalTo(-bodyPadding)
      }
      if headerView != nil {
        make.top.equalTo(headerView!.snp.bottom).offset(topPadding)
      } else {
        make.top.equalTo(topMargin)
      }
      make.height.equalTo(bodyHeight)
    }
#endif
  }
    
  private func setupFooterView() {
    guard let footerView = footerView else { return }
    contentView.addSubview(footerView)
#if canImport(SnapKit)
    footerView.snp.makeConstraints { make in
      if footerHorizon {
        make.width.equalTo(footerWidth)
        make.centerX.equalToSuperview()
      } else {
        make.left.equalTo(footerPadding)
        make.right.equalTo(-footerPadding)
      }
      make.bottom.equalTo(-bottomMargin)
      make.height.equalTo(footerHeight)
    }
#endif
  }
    
  // MARK: - Helper Methods
    
  private func viewWithData(_ data: Any?, type: Int) -> UIView? {
    guard let data = data else {
      switch type {
      case 0: headerHeight = 0
      case 1: bodyHeight = 0
      case 2: footerHeight = 0
      default: break
      }
      return nil
    }
        
    if let view = data as? UIView {
      return view
    } else if data is Int || data is YHToastPopViewType {
      let num = if let n = data as? Int {
        n
      } else if let type = data as? YHToastPopViewType {
        Int(type.rawValue)
      } else {
        0
      }
      if type == 0 {
        headerHorizon = true
        headerHeight = 64
      }
      switch num {
        #warning("todo")
      case 1: return UIImageView()
      case 2: return UIImageView(named: "toast_error")
      case 3: return UIImageView(named: "toast_success")
      default: return nil
      }
    } else if let image = data as? UIImage {
      if type == 2 {
        return UIButton(image: image)
      }
      if type == 0 {
        headerHeight = 64
      }
      return UIImageView(image: image)
    } else if data is String || data is AString {
      let text = if let str = data as? String {
        str.isEmpty ? (type == 2 ?"Got it".local : "Tips".local) : str
      } else {
        data
      }
      switch type {
      case 0:
        let label = UILabel(text, font: .num(17, .bold), color: .label)
        label.numberOfLines = 0
        label.textAlignment = headerAlign
        headerHeight = max(label.textHeight(contentWidth - headerPadding * 2), headerHeight)
        return label
      case 1:
        let textView = UITextView(text, font: .num(15, .bold), color: .label)
        textView.textAlignment = bodyAlign
        textView.isEditable = false
        bodyHeight = min(bodyHeight, textView.textHeight(contentWidth - bodyPadding * 2))
        return textView
      case 2:
        footerHorizon = true
        let button = UIButton.gradient(text, action: .SEL("buttonAction"), target: self)
        return button
      default:
        return nil
      }
    } else {
      return nil
    }
  }
    
  // MARK: - Actions
    
  @objc private func buttonAction() {
    dismiss()
  }
    
  // MARK: - Deinitialization
    
  deinit {
    timer?.invalidate()
    timer = nil
    print("APToastPopView deinitialized")
  }
}

public extension YHToastPopView {
  @objc static func popForcely(_ properties: [YHPopProperty: Any], on view: UIView? = nil, eventBlock: ((Any?) -> Void)? = nil) {
    var info = properties
    info[.header] = info[.header] == nil ? "" : info[.header]
    info[.footer] = info[.footer] == nil ? "" : info[.footer]
    pop(properties: info, on: view, eventBlock: eventBlock)
  }
}
